<template>
  <n-spin :show="mainStore.pageLoading" class="plan-container">
    <div class="text-center pb-6">
      <n-h2>套餐订阅</n-h2>
      <n-h4 class="my-6">请按需选择最适合您的套餐方案</n-h4>
      <n-h5>
        当前套餐
        {{ userStore.edition === 'free' ? '状态：免费版' : '到期时间：' + timeFormat(userStore.expiration_at) }}
      </n-h5>
    </div>
    <n-grid cols="3 xs:1 s:2 m:2 l:3 xxl:3" responsive="screen" x-gap="20" y-gap="20">
      <n-gi v-for="item in planState.list" :key="item.id">
        <n-card :bordered="false" class="shadow">
          <div class="flex flex-col justify-center items-center">
            <n-h2 class="font-bold mt-4">
              {{ item.name }}
            </n-h2>
            <n-tag type="error" size="small" class="mt-4 dark:bg-error/70 dark:text-white">
              {{ item.remarks }}
            </n-tag>
            <div class="my-6 w-20 h-20 flex justify-center items-center rounded-full bg-slate-200 dark:bg-gray-500">
              <n-icon :component="DiamondOutline" size="40" class="mt-1.5" />
            </div>
            <div class="text-center mb-6">
              <del class="n-h5 font-bold mb-0 text-gray-500 dark:text-gray-400">
                ￥{{ item.old_price }}/{{ switchDay(item.day) }}
              </del>
              <div class="mb-2 flex justify-center">
                <span class="n-h4 mt-3 mb-0 mr-1">￥</span>
                <n-h1 class="font-bold mb-0 text-4xl">{{ item.now_price }}</n-h1>
                <sub class="n-h4 mt-auto mb-2">/{{ switchDay(item.day) }}</sub>
              </div>
            </div>
          </div>
          <n-descriptions :column="1" :separator="''" class="pl-3" label-placement="left" size="large">
            <n-descriptions-item>
              <template #label>
                <n-icon :component="CheckmarkCircle" class="text-primary" />
                套餐时长：
              </template>
              {{ item.day }} 天
            </n-descriptions-item>
            <n-descriptions-item v-for="text in unref(planState.content)" :key="text">
              <template #label>
                <n-icon :component="CheckmarkCircle" class="text-primary" />
                {{ text }}
              </template>
            </n-descriptions-item>
          </n-descriptions>
          <template #footer>
            <n-button block class="w-full" size="large" type="primary" @click="subscribeNow(item)">立即订阅</n-button>
          </template>
        </n-card>
      </n-gi>
    </n-grid>
  </n-spin>

  <BasicModal
    title="订阅套餐"
    to=".plan-container"
    class="w-auto max-w-[520px] s:mx-auto"
    :mask-closable="false"
    @register="payModalRegister"
    @after-leave="afterPayLeave"
  >
    <n-space v-if="!planState.paymentMethod" vertical align="center" :size="20" class="xs:w-[280px] s:w-[400px]">
      <n-text class="text-lg">选择支付方式</n-text>
      <n-grid x-gap="20" y-gap="20" cols="2 xs:1 s:2" responsive="screen">
        <n-gi>
          <n-space vertical align="center">
            <n-button class="w-36 h-36" size="large" ghost color="#009FE8" @click="handlePay('alipay')">
              <template #icon>
                <n-icon :component="LogoAlipay" size="50" />
              </template>
            </n-button>
            <n-text class="font-bold text-base" color="#009FE8">支付宝</n-text>
          </n-space>
        </n-gi>
        <n-gi>
          <n-space vertical align="center">
            <n-button class="w-36 h-36" size="large" ghost color="#15BA11" @click="handlePay('wechat')">
              <img alt="wechat" :src="getImageUrl('plan', 'wechat_pay')" width="50" />
            </n-button>
            <n-text class="font-bold text-base" color="#15BA11">微信支付</n-text>
          </n-space>
        </n-gi>
      </n-grid>
    </n-space>
    <div v-if="planState.paymentMethod" class="s:w-[450px]">
      <n-alert class="mb-4" title="" type="warning" :bordered="false">
        付款成功前请不要关闭此窗口，请按实际情况点击下方按钮。
      </n-alert>
      <n-card v-if="planState.paymentMethod === 'alipay'" class="pay-card" :bordered="false">
        <n-text class="text-lg">请在新打开的页面完成付款</n-text>
        <n-text class="text-base mt-2">订单号：{{ planState.order_number }}</n-text>
        <n-h4 class="flex justify-center items-baseline mt-2">
          支付金额：￥
          <n-text class="font-bold mb-0 text-2xl">{{ planState.selectPlan?.now_price }}</n-text>
        </n-h4>
      </n-card>
      <n-card v-if="planState.paymentMethod === 'wechat'" class="pay-card" :bordered="false">
        <n-text class="text-lg">微信扫码支付</n-text>
        <n-text class="text-base">订单号：{{ planState.order_number }}</n-text>
        <n-spin class="qrcode-spin" :show="planState.loading">
          <div v-if="!planState.qrcodeUrl && !planState.loading" class="qrcode-expired">
            <n-text class="text-white/80">二维码已超时</n-text>
            <n-button type="primary" @click="getWxPayQrcode">刷新</n-button>
          </div>
          <qrcode-vue
            class="my-4 border rounded"
            :value="planState.qrcodeUrl"
            render-as="svg"
            :margin="2"
            :size="240"
            level="L"
          />
        </n-spin>
        <n-h4 class="flex justify-center items-baseline">
          支付金额：￥
          <n-text class="font-bold mb-0 text-2xl">{{ planState.selectPlan?.now_price }}</n-text>
        </n-h4>
      </n-card>
    </div>
    <template #action>
      <div v-if="planState.paymentMethod" class="w-full flex justify-center gap-4">
        <n-button type="default" size="large" @click="basicClosePayModal">取消支付</n-button>
        <n-button type="primary" size="large" :loading="planState.checkIng" @click="payComplete">付款成功</n-button>
      </div>
      <div v-else></div>
    </template>
  </BasicModal>
</template>

<script setup>
import { reactive, defineAsyncComponent, unref } from 'vue'
import { planList, wechatBuy, alipay, checkOrder } from '@api/payApi'
import { CheckmarkCircle, DiamondOutline, LogoAlipay } from '@vicons/ionicons5'
import { useModal } from '@cmps/Modal/useModal'
import { useUserStore, useMainStore } from '@/store'
import { useRouter } from 'vue-router'
import { useDialog } from '@/hook/useDialog'
import { getImageUrl, isWeiXin, isMobile, timeFormat, MiniProgramJump, isMiniProgram } from '@/utils'

const QrcodeVue = defineAsyncComponent(() => import('qrcode.vue'))
const BasicModal = defineAsyncComponent(() => import('@cmps/Modal/BasicModal.vue'))

const router = useRouter()
const userStore = useUserStore()
const mainStore = useMainStore()

const planState = reactive({
  list: [],
  loading: false,
  qrcodeUrl: '',
  order_number: null,
  selectPlan: {},
  second: 0,
  checkOrderTimer: null,
  checkIng: false,
  paymentMethod: '',
  content: [
    '支持推广续费',
    '对话次数无限制',
    '对话消息实时回显',
    '支持会话内容多格式导出',
    '付费专享AI服务器',
    '多节点服务器负载均衡',
  ],
})

const [payModalRegister, { openModal: basicOpenPayModal, closeModal: basicClosePayModal }] = useModal({})

const getPlanList = async () => {
  try {
    mainStore.setPageLoading(true)
    const res = await planList()
    if (res.statusCode === 200) {
      planState.list = res.data
    }
  } finally {
    mainStore.setPageLoading(false)
  }
}
getPlanList()

const handlePay = async type => {
  planState.paymentMethod = type
  switch (type) {
    case 'wechat':
      getWxPayQrcode()
      break
    case 'alipay':
      try {
        planState.second = 0
        planState.loading = true
        const res = await alipay({
          plan_id: planState.selectPlan.id,
          return_url: location.href,
        })
        if (res.statusCode === 200) {
          const { form, order_number } = res.data
          planState.order_number = order_number
          $message.loading('正在发起支付中', { duration: 1000 })
          setTimeout(() => {
            planState.checkOrderTimer = setInterval(checkOrderStatus, 2000)
            const routerData = router.resolve({ path: '/alipay', query: { htmlData: form } })
            window.open(`${location.origin}${routerData.href}`, '_blank')
          }, 1000)
        }
      } finally {
        planState.loading = false
      }
      break
  }
}

const isMobileWechat = () => {
  return isWeiXin() && isMobile()
}

const subscribeNow = plan => {
  planState.selectPlan = { ...plan }
  if (!isMobileWechat()) {
    basicOpenPayModal()
  } else {
    wechatPay()
  }
}

const backChat = () => {
  useDialog({
    type: 'success',
    icon: true,
    title: '支付成功',
    content: '已成功开通套餐，是否返回对话？',
    negative: '',
    async confirm() {
      await router.replace('/chat/new')
    },
  })
}

const wechatPay = async () => {
  if (await isMiniProgram()) {
    //微信小程序支付
    MiniProgramJump({
      url: `/pages/pay/pay?data=${JSON.stringify({
        body: {
          plan_id: planState.selectPlan.id,
        },
        good: planState.list.find(item => item.id === planState.selectPlan.id),
        token: userStore.token,
      })}`,
    })
  } else {
    const res = await wechatBuy({ type: 'JSAPI', plan_id: planState.selectPlan.id })
    if (res.statusCode === 200) {
      const { appid, prepay_id, randomStr, signature, timestamp } = res.data
      if (WeixinJSBridge) {
        WeixinJSBridge.invoke(
          'getBrandWCPayRequest',
          {
            appId: appid, //公众号ID，由商户传入
            timeStamp: timestamp, //时间戳，自1970年以来的秒数
            nonceStr: randomStr, //随机串
            package: `prepay_id=${prepay_id}`,
            signType: 'RSA', //微信签名方式：
            paySign: signature, //微信签名
          },
          async function (res) {
            if (res.err_msg == 'get_brand_wcpay_request:ok') {
              // 使用以上方式判断前端返回,微信团队郑重提示：
              // res.err_msg将在用户支付成功后返回ok，但并不保证它绝对可靠。
              await userStore.getUserInfo()
              backChat()
            } else {
              $message.warning('暂未支付', { duration: 1500 })
            }
          }
        )
      }
    }
  }
}

const getWxPayQrcode = async () => {
  try {
    planState.second = 0
    planState.loading = true
    const res = await wechatBuy({ type: 'Native', plan_id: planState.selectPlan.id })
    if (res.statusCode === 200) {
      planState.qrcodeUrl = res.data.code_url
      planState.order_number = res.data.order_number
      planState.checkOrderTimer = setInterval(checkOrderStatus, 2000)
    }
  } finally {
    planState.loading = false
  }
}

const checkOrderStatus = async () => {
  try {
    planState.second += 2
    if (planState.paymentMethod === 'wechat') {
      const res = await checkOrder({ order_number: planState.order_number })
      if (res.statusCode === 200) {
        if (res.state === 1) {
          basicClosePayModal()
          await userStore.getUserInfo()
          backChat()
        }
      }
    }
  } finally {
    if (planState.second >= 300) {
      afterPayLeave()
    }
  }
}

const payComplete = async () => {
  try {
    planState.checkIng = true
    const res = await checkOrder({ order_number: planState.order_number })
    if (res.statusCode === 200) {
      if (res.state === 1) {
        basicClosePayModal()
        await userStore.getUserInfo()
        backChat()
      } else {
        $message.warning('暂未支付', { duration: 1500 })
      }
    }
  } finally {
    planState.checkIng = false
  }
}

const afterPayLeave = () => {
  if (planState.paymentMethod === 'alipay' && planState.second >= 300) {
    basicClosePayModal()
    useDialog({
      type: 'error',
      icon: true,
      title: '提示',
      content: '当前支付已超时！',
      negative: '',
      confirm() {},
    })
  }
  planState.qrcodeUrl = ''
  planState.order_number = null
  planState.loading = false
  clearInterval(planState.checkOrderTimer)
  planState.checkOrderTimer = null
  planState.second = 0
  planState.paymentMethod = ''
}

const switchDay = day => {
  switch (day) {
    case 1:
      return '天'
    case 7:
      return '周'
    case 30:
      return '月'
    case 90:
      return '季'
    case 365:
      return '年'
  }
}
</script>

<style lang="less" scoped>
.plan-container {
  &:deep(.n-grid) {
    max-width: 1200px;
    margin: 0 auto;
    .n-card {
      .n-card__content {
        padding: 24px !important;
        .n-descriptions-table-content {
          display: flex;
          .n-descriptions-table-content__label {
            display: flex;
            .n-icon {
              font-size: 20px;
              margin-right: 8px;
            }
          }
        }
        .n-descriptions-table-content__content {
          font-weight: 600;
        }
      }
    }
  }

  &:deep(.pay-card) {
    .n-card__content {
      padding: 0 0 14px;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      .qrcode-spin {
        .n-spin-content {
          position: relative;
          .qrcode-expired {
            width: 100%;
            height: 100%;
            position: absolute;
            z-index: 10;
            left: 0;
            top: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            gap: 10px;
            backdrop-filter: saturate(150%) contrast(50%) blur(8px);
            -webkit-backdrop-filter: saturate(150%) contrast(50%) blur(8px);
            background-color: rgba(0, 0, 0, 0.3);
          }
        }
      }
    }
  }
}
</style>
